-- -------------------------------------------------------------------
--																	--
--			== MonsterTPMoves.lua ==								--
--																	--
--  Contains functions for damage and use of Mob TP moves.			--
--																	--
--	Foreword: A lot of this is good estimating since the FFXI		--
--	playerbase has not found all of info for individual moves. What	--
--	is known is that they roughly follow player Weaponskill			--
--	calculations (pDIF, dMOD, ratio, etc) so this is what this set	--
--	of functions emulates.											--
--																	--
-- -------------------------------------------------------------------

require("scripts/globals/magic");
require("scripts/globals/magicburst")
require("scripts/globals/status")
require("scripts/globals/utils")


-- -------------------------------------------------------------------
--																	--
--		Mob Types			used in mob:isMobType()					--
--																	--
-- -------------------------------------------------------------------

MOBTYPE_NORMAL			= 0x00;
MOBTYPE_PCSPAWNED		= 0x01;
MOBTYPE_NOTORIOUS		= 0x02;
MOBTYPE_FISHED			= 0x04;
MOBTYPE_CALLED			= 0x08;
MOBTYPE_BATTLEFIELD		= 0x10;
MOBTYPE_EVENT			= 0x20;

-- -------------------------------------------------------------------
--																	--
--		Mobskill Types												--
--																	--
-- -------------------------------------------------------------------

MOBSKILL_PHYSICAL	= 0;
MOBSKILL_MAGICAL	= 1;
MOBSKILL_RANGED		= 2;
MOBSKILL_BREATH		= 4;
MOBSKILL_SPECIAL	= 3;

-- -------------------------------------------------------------------
--																	--
--		Mob TP Move Skill Parameter (PHYSICAL)						--
--																	--
-- -------------------------------------------------------------------

MOBPARAM_NONE		= 0;
MOBPARAM_BLUNT		= 1;
MOBPARAM_SLASH		= 2;
MOBPARAM_PIERCE		= 3;
MOBPARAM_H2H		= 4;

-- -------------------------------------------------------------------
--																	--
--		Mob TP Move Skill Parameter (MAGICAL)						--
--																	--
--	This is totally useless and should be removed add resistence	--
--	using ELE_FIRE, see bomb_toss.lua								--
--																	--
-- -------------------------------------------------------------------

MOBPARAM_FIRE		= 6;
MOBPARAM_EARTH		= 7;
MOBPARAM_WATER		= 8;
MOBPARAM_WIND		= 9;
MOBPARAM_ICE		= 10;
MOBPARAM_THUNDER	= 11;
MOBPARAM_LIGHT		= 12;
MOBPARAM_DARK		= 13;

-- -------------------------------------------------------------------
--																	--
--		Mob TP Move Skill Parameter (shadowbehav)					--
--																	--
--		Number of shadows to take off.								--
--																	--
-- -------------------------------------------------------------------

MOBPARAM_IGNORE_SHADOWS = 0;
MOBPARAM_1_SHADOW		= 1;
MOBPARAM_2_SHADOW		= 2;
MOBPARAM_3_SHADOW		= 3;
MOBPARAM_4_SHADOW		= 4;
MOBPARAM_WIPE_SHADOWS	= 999;

-- -------------------------------------------------------------------
--																	--
--		Mob TP Move Skill Parameter (TP Effect Type)				--
--																	--
-- -------------------------------------------------------------------

TP_ACC_VARIES	= 0;
TP_ATK_VARIES	= 1;
TP_DMG_VARIES	= 2;
TP_CRIT_VARIES	= 3;
TP_NO_EFFECT	= 0;
TP_MACC_BONUS	= 1;
TP_MAB_BONUS	= 2;
TP_DMG_BONUS	= 3;
TP_RANGED		= 4;

-- -------------------------------------------------------------------
--																	--
--		Mob TP Move Skill Parameter (Message)						--
--																	--
-- -------------------------------------------------------------------

MSG_NONE			= 0;	-- Display nothing
MSG_USES			= 101;	-- Simple uses message
MSG_FAMILIAR		= 108;
MSG_SELF_HEAL		= 238;
MSG_ENFEEB_IS		= 242;	--XXX is petrified.
MSG_ENFEEB			= 243;	--XXX receives the effect of petrification.
MSG_BUFF			= 186;
MSG_DRAIN_HP		= 187;
MSG_DRAIN_MP		= 225;
MSG_DRAIN_TP		= 226;
MSG_NO_EFFECT		= 189;
MSG_SHADOW			= 31;
MSG_ANTICIPATE		= 30;
MSG_DAMAGE			= 185;	-- Player uses, target takes 10 damage. DEFAULT
MSG_MISS			= 188;
MSG_RESIST			= 85;
MSG_EFFECT_DRAINED	= 370;	-- <num> status effects are drained from <target>.
MSG_TP_REDUCED		= 362;	-- TP reduced to
MSG_DISAPPEAR		= 159;	-- <target>'s stun effect disappears!
MSG_DISAPPEAR_NUM	= 231;	-- <num> of <target>'s effects disappear!

BOMB_TOSS_HPP		= 1;

-- -------------------------------------------------------------------
--																	--
--		== MobRangedMove ==											--
--	(mob,target,skill,numberofhits,accmod,dmgmod, tpeffect)			--
--																	--
-- -------------------------------------------------------------------

function MobRangedMove(mob,target,skill,numberofhits,accmod,dmgmod, tpeffect)
	-- This will eventually contian ranged attack code
	return MobPhysicalMove(mob,target,skill,numberofhits,accmod,dmgmod, TP_RANGED);
end;

-- -------------------------------------------------------------------
--																	--
--		== MobPhysicalMove ==	Call this on every physical move!	--
--																	--
--		accmod is a linear multiplier for accuracy (1 default)		--
--		dmgmod is a linear mulitplier for damage (1 default)		--
--		tpeffect is an enum which can be one of:					--
--			0 TP_ACC_VARIES		2 TP_DMG_VARIES						--
--			1 TP_ATK_VARIES		3 TP_CRIT_VARIES					--
--		mtp100/200/300 are the three values for						--
--		100% TP, 200% TP, 300% TP just like weaponskills.lua		--
--	if TP_ACC_VARIES -> three values are acc %s (1.0 is 100% acc,	--
--		0.8 is 80% acc, 1.2 is 120% acc)							--
--	if TP_ATK_VARIES -> three values are attack multiplier			--
--		(1.5x 0.5x etc)												--
--	if TP_DMG_VARIES -> three values are							--
--																	--
-- -------------------------------------------------------------------

function MobPhysicalMove(mob,target,skill,numberofhits,accmod,dmgmod,tpeffect,mtp000,mtp150,mtp300)
	local returninfo = {};

	-- Get dSTR (bias to monsters, so no fSTR)
	local dstr = mob:getStat(MOD_STR) - target:getStat(MOD_VIT);
	if(dstr < -10) then
		dstr = -10;
	end

	if(dstr > 10) then
		dstr = 10;
	end

	local lvluser = mob:getMainLvl();
	local lvltarget = target:getMainLvl();
	local acc = mob:getACC();
	local eva = target:getEVA();
	-- Apply WSC
	local base = mob:getWeaponDmg() + dstr; -- TODO: change to include WSC
	if(base < 1) then
		base = 1;
	end

	-- Work out and cap ratio
	local ratio = mob:getStat(MOD_ATT)/target:getStat(MOD_DEF);
	ratio = utils.clamp(ratio, 0, 2);

	local lvldiff = lvluser - lvltarget;
	if lvldiff < 0 then
		lvldiff = 0;
	end

	ratio = ratio + lvldiff * 0.05;
	ratio = utils.clamp(ratio, 0, 4);

	-- Work out hit rate for mobs (bias towards them)
	local hitrate = (acc*accmod) - eva + (lvldiff*3) + 85;

	-- printf("acc: %f, eva: %f, hitrate: %f", acc, eva, hitrate);
	if (hitrate > 95) then
		hitrate = 95;
	elseif (hitrate < 20) then
		hitrate = 20;
	end

	-- Work out the base damage for a single hit
	local hitdamage = (base + lvldiff);
	if(hitdamage < 1) then
		hitdamage = 1;
	end

	hitdamage = hitdamage * dmgmod * MobTPMod(skill:getTP());

	-- Work out min and max cRatio
	local maxRatio = 1;
	local minRatio = 0;

	if(ratio < 0.5) then
		maxRatio = ratio + 1;
	elseif((0.5 <= ratio) and (ratio <= 0.7)) then
		maxRatio = 1;
	elseif((0.7 < ratio) and (ratio <= 1.2)) then
		maxRatio = ratio + 0.3;
	elseif((1.2 < ratio) and (ratio <= 1.5)) then
		maxRatio = (ratio * 0.25) + ratio;
	elseif((1.5 < ratio) and (ratio <= 2.625)) then
		maxRatio = ratio + 0.375;
	elseif((2.625 < ratio) and (ratio <= 3.25)) then
		maxRatio = 3;
	else 
		maxRatio = ratio;
	end

	if(ratio < 0.38) then
		minRatio =  0;
	elseif((0.38 <= ratio) and (ratio <= 1.25)) then
		minRatio = ratio * (1176 / 1024) - (448 / 1024);
	elseif((1.25 < ratio) and (ratio <= 1.51)) then
		minRatio = 1;
    elseif ((1.51 < ratio) and (ratio <= 2.44)) then
        minRatio = ratio * (1176 / 1024) - (775 / 1024);
    else
        minRatio = ratio - 0.375;
    end

	-- Apply fTP (assumes 1~3 scalar linear mod)
	if(tpeffect==TP_DMG_BONUS) then
		hitdamage = hitdamage * fTP(skill:getTP(), mtp000, mtp150, mtp300);
	end

	-- Applying pDIF
	local pdif = 0;

	-- Start the hits
	local hitchance = math.random();
	local finaldmg		= 0;
	local hitsdone		= 1;
	local hitslanded	= 0;

	local chance = math.random();

	-- First hit has a higher chance to land
	local firstHitChance = hitrate * 1.5;

	if(tpeffect==TP_RANGED) then
		firstHitChance = hitrate * 1.2;
	end

	firstHitChance = utils.clamp(firstHitChance, 60, 95);

	if ((chance*100) <= firstHitChance) then
		pdif = math.random((minRatio*1000),(maxRatio*1000)) -- Generate random pDIF
		pdif = pdif/1000; -- Multiplier set.
		finaldmg = finaldmg + hitdamage * pdif;
		hitslanded = hitslanded + 1;
	end
	while (hitsdone < numberofhits) do
		chance = math.random();
		if ((chance*100)<=hitrate) then --it hit
			pdif = math.random((minRatio*1000),(maxRatio*1000)) -- Generate random pDIF
			pdif = pdif/1000; -- Multiplier set.
			finaldmg = finaldmg + hitdamage * pdif;
			hitslanded = hitslanded + 1;
		end
		hitsdone = hitsdone + 1;
	end

	-- printf("final: %f, hits: %f, acc: %f", finaldmg, hitslanded, hitrate);

	-- If an attack landed it must do at least 1 damage
	if(hitslanded >= 1 and finaldmg < 1) then
		finaldmg = 1;
	end

	-- All hits missed
	if(hitslanded == 0 or finaldmg == 0) then
		finaldmg = 0;
		hitslanded = 0;
		skill:setMsg(MSG_MISS);
	end

	returninfo.dmg = finaldmg;
	returninfo.hitslanded = hitslanded;

	return returninfo;

end

-- -------------------------------------------------------------------
--																	--
--		== MobMagicalMove ==	Call this on every magical move!	--
--																	--
--	mob/target/skill should be passed from OnMobWeaponSkill.		--
--	dmg is the base damage (V value), accmod is a multiplier for	--
--	accuracy (1 default, more than 1 = higher macc for mob),		--
--	ditto for dmg mod but more damage >1 (equivalent of M value)	--
--	tpeffect is an enum from one of:								--
--		0 = TP_NO_EFFECT		2 = TP_MAB_BONUS					--
--		1 = TP_MACC_BONUS		3 = TP_DMG_BONUS					--
--	tpvalue affects the strength of having more TP along the		--
--	following lines:
--		TP_NO_EFFECT -> tpvalue has no effect.						--
--		TP_MACC_BONUS -> direct multiplier to macc (1 for default)	--
--		TP_MAB_BONUS -> direct multiplier to mab (1 for default)	--
--		TP_DMG_BONUS -> direct multiplier to damage (V+dINT)		--
--			(1 for default)											--
--	Examples:														--
--		TP_DMG_BONUS and TP=100, tpvalue = 1, assume V=150  -->		--
--			damage is now 150*(TP*1)/100 = 150						--
--		TP_DMG_BONUS and TP=200, tpvalue = 1, assume V=150  -->		--
--			damage is now 150*(TP*1)/100 = 300						--
--		TP_DMG_BONUS and TP=100, tpvalue = 2, assume V=150  -->		--
--			damage is now 150*(TP*2)/100 = 300						--
--		TP_DMG_BONUS and TP=200, tpvalue = 2, assume V=150  -->		--
--			damage is now 150*(TP*2)/100 = 600						--
--																	--
-- -------------------------------------------------------------------

function MobMagicalMove(mob,target,skill,damage,element,dmgmod,tpeffect,tpvalue)
	returninfo = {};
	-- Get all the stuff we need
	local resist = 1;

	-- Plus 100 forces it to be a number
	mab = (100+mob:getMod(MOD_MATT)) / (100+target:getMod(MOD_MDEF));
	
	if (mab > 1.3) then
		mab = 1.3;
	end

	if (mab < 0.7) then
		mab = 0.7;
	end

	if(tpeffect==TP_DMG_BONUS) then
		damage = damage * ((skill:getTP()*tpvalue)/100);
	end

	-- printf("power: %f, bonus: %f", damage, mab);
	-- Resistence is added last
	finaldmg = damage * mab * dmgmod;

	-- Get resistence
	resist = applyPlayerResistance(mob,-1,target,mob:getStat(MOD_INT)-target:getStat(MOD_INT),0,element);

	-- Get elemental damage reduction
	local defense = 1;
	if(element > 0) then
		defense = 1 + (target:getMod(defenseMod[element]) / -1000);

		-- Max defense is 50%
		if(defense < 0.5) then
			defense = 0.5;
		end
	end

	finaldmg = finaldmg * resist * defense;

	returninfo.dmg = finaldmg;

	return returninfo;

end

-- -------------------------------------------------------------------
--																	--
--		== applyPlayerResistance ==			Mob version				--
--	(mob,effect,target,diff,bonus,element)							--
--																	--
--	effect = EFFECT_WHATEVER if enfeeble							--
--	statmod = the stat to account for resist (INT,MND,etc)			--
--	e.g. MOD_INT													--
--	This determines how much the monsters ability resists on the	--
--	player.															--
--	TODO: update all mob moves to use the new function				--
--																	--
-- -------------------------------------------------------------------

function applyPlayerResistance(mob,effect,target,diff,bonus,element)
    resist = 1.0;
    magicaccbonus = 0;

	-- Get the base acc (just skill plus magic acc mod)
	magicacc = getSkillLvl(1, mob:getMainLvl()) + bonus;

	-- Difference in INT/MND
	if diff > 10 then
		magicacc = magicacc + 10 + (diff - 10)/2;
	else
		magicacc = magicacc + diff;
	end

	-- Base magic evasion (base magic evasion plus resistances(players), plus elemental defense(mobs)
	local magiceva = target:getMod(MOD_MEVA);

	-- Add elemental resistence
	if(element > 0) then
		magiceva = magiceva + target:getMod(resistMod[element]);
	end

	p = magicacc - (magiceva * 0.8);

	-- printf("acc: %f, eva: %f, bonus: %f", magicacc, magiceva, magicaccbonus);
	-- Double any ACC over 50 if it's over 50
	if(p > 5) then
		p = 5 + (p - 5) * 2;
	end

	-- Add a flat bonus that won't get doubled in the previous step
	p = p + 45;

	-- Add a scaling bonus or penalty based on difference of targets level from caster
	leveldiff = mob:getMainLvl() - target:getMainLvl();
	if leveldiff > 0 then
		p = p - (25 * ( (mob:getMainLvl()) / 75 )) + leveldiff;
	else
		p = p + (25 * ( (mob:getMainLvl()) / 75 )) + leveldiff;
	end

	-- printf("final power: %f", p);
	-- Cap accuracy
    if(p > 95) then
        p = 95;
    elseif(p < 5) then
        p = 5;
    end

	p = p / 100;

    -- Resistance thresholds based on p.  A higher p leads to lower resist rates, and a lower p leads to higher resist rates.
    half = (1 - p);
    quart = ((1 - p)^2);
    eighth = ((1 - p)^3);
    sixteenth = ((1 - p)^4);
    -- printf("HALF: %f", half);
    -- printf("QUART: %f", quart);
    -- printf("EIGHTH: %f", eighth);
    -- printf("SIXTEENTH: %f", sixteenth);

	-- Add effect resistence
	-- This only increases chances for half / quarter resist
	-- This eventually needs to be fixed
	-- Traits should be able to fully resist
	if(effect ~= nil and effect > 0) then
		local effectres = 0;
		if(effect == EFFECT_SLEEP_I or effect == EFFECT_SLEEP_II or effect == EFFECT_LULLABY) then
			effectres = MOD_SLEEPRES;
		elseif(effect == EFFECT_POISON) then
			effectres = MOD_POISONRES;
		elseif(effect == EFFECT_PARALYZE) then
			effectres = MOD_PARALYZERES;
		elseif(effect == EFFECT_BLIND) then
			effectres = MOD_BLINDRES
		elseif(effect == EFFECT_SILENCE) then
			effectres = MOD_SILENCERES;
		elseif(effect == EFFECT_PLAGUE or effect == EFECT_DISEASE) then
			effectres = MOD_VIRUSRES;
		elseif(effect == EFFECT_PETRIFICATION) then
			effectres = MOD_PETRIFYRES;
		elseif(effect == EFFECT_BIND) then
			effectres = MOD_BINDRES;
		elseif(effect == EFFECT_CURSE_I or effect == EFFECT_CURSE_II or effect == EFFECT_BANE) then
			effectres = MOD_CURSERES;
		elseif(effect == EFFECT_WEIGHT) then
			effectres = MOD_GRAVITYRES;
		elseif(effect == EFFECT_SLOW) then
			effectres = MOD_SLOWRES;
		elseif(effect == EFFECT_STUN) then
			effectres = MOD_STUNRES;
		elseif(effect == EFFECT_CHARM) then
			effectres = MOD_CHARMRES;
		end

		if(effectres > 0) then
			local resrate = 1+(target:getMod(effectres)/20);
			if(resrate > 1.5) then
				resrate = 1.5;
			end

			-- printf("Resist percentage: %f", resrate);
			-- Increase resistance based on effect
			quart = quart * resrate;
			half = half * resrate;
		end
	end

    resvar = math.random();

    -- Determine final resist based on which thresholds have been crossed.
    if(resvar <= sixteenth) then
        resist = 0.0625;
        -- printf("Spell resisted to 1/16!!!  Threshold = %u",sixteenth);
    elseif(resvar <= eighth) then
        resist = 0.125;
        -- printf("Spell resisted to 1/8!  Threshold = %u",eighth);
    elseif(resvar <= quart) then
        resist = 0.25;
        -- printf("Spell resisted to 1/4.  Threshold = %u",quart);
    elseif(resvar <= half) then
        resist = 0.5;
        -- printf("Spell resisted to 1/2.  Threshold = %u",half);
    else
        resist = 1.0;
        -- printf("Not resisted: 1.0");
    end
    return resist;

end;

-- -------------------------------------------------------------------
--																	--
--		== mobAddBonuses ==		(caster, spell, target, dmg, ele)	--
--																	--
--	Species, weather, day, mag. accuracy, mag. damage bonuses		--
--																	--
-- -------------------------------------------------------------------

function mobAddBonuses(caster, spell, target, dmg, ele)

	speciesReduction = target:getMod(defenseMod[ele]);
	speciesReduction = 1.00 - (speciesReduction/1000);
	dmg = math.floor(dmg * speciesReduction);

	dayWeatherBonus = 1.00;

	if caster:getWeather() == singleWeatherStrong[ele] then
		if math.random() < 0.33 then
			dayWeatherBonus = dayWeatherBonus + 0.10;
		end
	elseif caster:getWeather() == singleWeatherWeak[ele] then
		if math.random() < 0.33 then
			dayWeatherBonus = dayWeatherBonus - 0.10;
		end
	elseif caster:getWeather() == doubleWeatherStrong[ele] then
		if math.random() < 0.33 then
			dayWeatherBonus = dayWeatherBonus + 0.25;
		end
	elseif caster:getWeather() == doubleWeatherWeak[ele] then
		if math.random() < 0.33 then
			dayWeatherBonus = dayWeatherBonus - 0.25;
		end
	end

	if VanadielDayElement() == dayStrong[ele] then
		if math.random() < 0.33 then
			dayWeatherBonus = dayWeatherBonus + 0.10;
		end
	elseif VanadielDayElement() == dayWeak[ele] then
		if math.random() < 0.33 then
			dayWeatherBonus = dayWeatherBonus + 0.10;
		end
	end

	if dayWeatherBonus > 1.35 then
		dayWeatherBonus = 1.35;
	end

	dmg = math.floor(dmg * dayWeatherBonus);

    burst, burstBonus = calculateMobMagicBurstAndBonus(caster, ele, target);

	-- Not sure what to do for this yet
    -- if(burst > 1.0) then
		-- spell:setMsg(spell:getMagicBurstMessage()); -- "Magic Burst!"
	-- end

	dmg = math.floor(dmg * burst);

    mab = (100 + caster:getMod(MOD_MATT)) / (100 + target:getMod(MOD_MDEF)) ;

	dmg = math.floor(dmg * mab);

	magicDmgMod = (256 + target:getMod(MOD_DMGMAGIC)) / 256;

	dmg = math.floor(dmg * magicDmgMod);

	-- print(affinityBonus);
	-- print(speciesReduction);
	-- print(dayWeatherBonus);
	-- print(burst);
	-- print(mab);
	-- print(magicDmgMod);

    return dmg;
end

-- -------------------------------------------------------------------
--																	--
--		== calculateMobMagicBurstAndBonus ==						--
--																	--
--	Trigger Magic Burst and calculate the bonus.					--
--																	--
-- -------------------------------------------------------------------

function calculateMobMagicBurstAndBonus(caster, ele, target)

    local burst = 1.0;

    local skillchainTier, skillchainCount = MobFormMagicBurst(ele, target);

    if(skillchainTier > 0) then
		if(skillchainCount == 1) then
			burst = 1.3;
		elseif(skillchainCount == 2) then
			burst = 1.35;
		elseif(skillchainCount == 3) then
			 burst = 1.40;
		elseif(skillchainCount == 4) then
			burst = 1.45;
		elseif(skillchainCount == 5) then
			burst = 1.50;
		else
			-- Something strange is going on if this occurs.
			burst = 1.0;
		end
    end

    return burst, burstBonus;
end;

-- -------------------------------------------------------------------
--																	--
--		== MobBreathMove ==											--
--																	--
--	Calculates breath damage										--
--	Mob is a mob reference to get HP and LVL						--
--	Percent is the percentage to take from HP						--
--	Base is calculated from main level to create a minimum			--
--		Equation: (HP * percent) + (LVL / base)						--
--	Cap is optional, defines a maxiumum damage						--
--																	--
-- -------------------------------------------------------------------

function MobBreathMove(mob, target, percent, base, element, cap)
	local damage = (mob:getHP() * percent) + (mob:getMainLvl() / base);

	if(cap == nil) then
		-- super cap for high health mobs
		if(damage > 700) then
			damage = 700 + math.random(200);
		end

		-- Cap max damage
		if(damage > mob:getHP()/5) then
			damage = math.floor(mob:getHP()/5);
		end
	else
		if(damage > cap) then
			damage = cap;
		end
	end

	-- Elemental resistence
	if(element ~= nil and element > 0) then
		-- No skill available, pass nil
		-- Breath moves get a bonus accuracy because they are hard to resist
		local resist = applyPlayerResistance(mob,nil,target,mob:getStat(MOD_INT)-target:getStat(MOD_INT),mob:getMainLvl(),element);

		-- Get elemental damage reduction
		local defense = 1 - (target:getMod(resistMod[element]) + target:getMod(defenseMod[element])) / 256;

		-- Max defense is 50%
		if(defense < 0.5) then
			defense = 0.5;
		end

		damage = damage * resist * defense;
	end

	return damage;
end;

-- -------------------------------------------------------------------
--																	--
--		== MobFinalAdjustments ==									--
--		(dmg,mob,skill,target,skilltype,skillparam,shadowbehav)		--
--																	--
--	Take shadows, calculate the final damage taken, etc....			--
--																	--
-- -------------------------------------------------------------------

function MobFinalAdjustments(dmg,mob,skill,target,skilltype,skillparam,shadowbehav)

	-- Physical attack missed, skip rest
	if(skill:hasMissMsg()) then
		return 0;
	end

	-- Handle physical damage
	if((target:hasStatusEffect(EFFECT_PERFECT_DODGE) or target:hasStatusEffect(EFFECT_ALL_MISS) )
		and skilltype==MOBSKILL_PHYSICAL) then
		skill:setMsg(MSG_MISS);
		return 0;
	end

	-- Set message to damage
	-- This is for AoE because its only set once
	skill:setMsg(MSG_DAMAGE);

	-- Handle shadows depending on shadow behaviour / skilltype
	if(shadowbehav ~= MOBPARAM_WIPE_SHADOWS and shadowbehav ~= MOBPARAM_IGNORE_SHADOWS) then --remove 'shadowbehav' shadows.

		if(skill:isAoE() or skill:isConal()) then
			shadowbehav = MobTakeAoEShadow(mob, target, shadowbehav);
		end

		dmg = utils.takeShadows(target, dmg, shadowbehav);

		-- Dealt zero damage, so shadows took hit
		if(dmg == 0) then
			skill:setMsg(MSG_SHADOW);
			return shadowbehav;
		end

	elseif(shadowbehav == MOBPARAM_WIPE_SHADOWS) then -- Take em all!
		target:delStatusEffect(EFFECT_COPY_IMAGE);
		target:delStatusEffect(EFFECT_BLINK);
		target:delStatusEffect(EFFECT_THIRD_EYE);
	end

	if(skilltype == MOBSKILL_PHYSICAL and skill:isSingle() == false) then
		target:delStatusEffect(EFFECT_THIRD_EYE);
	end

	-- Handle Third Eye using shadowbehav as a guide
	if(skilltype == MOBSKILL_PHYSICAL and utils.thirdeye(target)) then
	    skill:setMsg(MSG_ANTICIPATE);
	    return 0;
	end

	dmg = utils.dmgTaken(target, dmg);
	if(target:hasStatusEffect(EFFECT_MANA_WALL) == true) then
		dmg = utils.manawall(target, dmg);
	end
	if(target:hasStatusEffect(EFFECT_SCARLET_DELIRIUM_I) == true) then
		utils.scarletDelirium(target, dmg);
	end

	if(skilltype == MOBSKILL_PHYSICAL) then

		dmg = utils.physicalDmgTaken(target, dmg);
		utils.dmgToTP(target, dmg);

	elseif(skilltype == MOBSKILL_MAGICAL) then

		dmg = utils.magicDmgTaken(target, dmg);

	elseif(skilltype == MOBSKILL_BREATH) then

		dmg = utils.breathDmgTaken(target, dmg);

	elseif(skilltype == MOBSKILL_RANGED) then

		dmg = utils.rangedDmgTaken(target, dmg);
		utils.dmgToTP(target, dmg);

	end

	-- Handling Phalanx
	dmg = dmg - target:getMod(MOD_PHALANX);

	if(dmg < 0) then
		return 0;
	end

	dmg = utils.stoneskin(target, dmg);
	utils.dmgToMP(target, dmg);

	if(dmg > 0) then
		target:wakeUp();
		target:updateEnmityFromDamage(mob,dmg);
	end

	return dmg;
end;

-- -------------------------------------------------------------------
--																	--
--		== MobPhysicalHit(skill) ==									--
--																	--
--	Returns true if mob attack hit, used to stop TP move status		--
--	effects.														--
--																	--
-- -------------------------------------------------------------------

function MobPhysicalHit(skill)
	-- If message is not the default. Then there was a miss, shadow taken etc
	return skill:hasMissMsg() == false;
end;

-- function MobHit()
-- end;

-- function MobAoEHit()
-- end;

-- function MobMagicHit()
-- end;

-- function MobMagicAoEHit()
-- end;

-- -------------------------------------------------------------------
--																	--
--		== MobStatusEffectMove ==									--
--	(mob, target, typeEffect, power, tick, duration)				--
--																	--
--	Adds a status effect to a target.								--
--																	--
-- -------------------------------------------------------------------

function MobStatusEffectMove(mob, target, typeEffect, power, tick, duration)

	if(target:canGainStatusEffect(typeEffect, power)) then
		local statmod = MOD_INT;
		local element = mob:getStatusEffectElement(typeEffect);

		local resist = applyPlayerResistance(mob,typeEffect,target,mob:getStat(statmod)-target:getStat(statmod),0,element);

		if(resist >= 0.25) then
			target:addStatusEffect(typeEffect,power,tick,duration*resist);
			return MSG_ENFEEB_IS;
		end

		return MSG_MISS; -- Resist !
	end
	return MSG_NO_EFFECT; -- No effect
end;

-- -------------------------------------------------------------------
--																	--
--		== MobPhysicalStatusEffectMove ==							--
--	(mob, target, skill, typeEffect, power, tick, duration)			--
--																	--
--	Adds a status effect to a target. Similar to status effect move	--
--	except, this will not land if the attack missed.				--
--																	--
-- -------------------------------------------------------------------

function MobPhysicalStatusEffectMove(mob, target, skill, typeEffect, power, tick, duration)

    if(MobPhysicalHit(skill)) then
        MobStatusEffectMove(mob, target, typeEffect, power, tick, duration);
    end
end;

-- -------------------------------------------------------------------
--																	--
--		== MobGazeMove ==											--
--	(mob, target,typeEffect, power, tick, duration)					--
--																	--
--	Adds a status effect to a target. Similar to status effect move	--
--	except, it will only take effect if facing the target.			--
--																	--
-- -------------------------------------------------------------------

function MobGazeMove(mob, target, typeEffect, power, tick, duration)
	if(target:isFacing(mob)) then
		return MobStatusEffectMove(mob, target, typeEffect, power, tick, duration);
	end
	return MSG_NO_EFFECT;
end;

-- -------------------------------------------------------------------
--																	--
--		== MobBuffMove ==											--
--	(mob, typeEffect, power, tick, duration)						--
--																	--
--	Adds a positive status effect to the mob(s).					--
--																	--
-- -------------------------------------------------------------------

function MobBuffMove(mob, typeEffect, power, tick, duration)

    if(mob:addStatusEffect(typeEffect,power,tick,duration)) then
	    return MSG_BUFF;
    end
	return MSG_NO_EFFECT;
end;

-- -------------------------------------------------------------------
--																	--
--		== MobHealMove ==		(target, heal)						--
--																	--
--	Heals the mob(s).												--
--																	--
-- -------------------------------------------------------------------

function MobHealMove(target, heal)

	local mobHP = target:getHP();
	local mobMaxHP = target:getMaxHP();

	if(mobHP+heal > mobMaxHP) then
		heal = mobMaxHP - mobHP;
	end

	target:wakeUp();

	target:addHP(heal);

	return heal;
end

-- -------------------------------------------------------------------
--																	--
--		== MobTakeAoEShadow ==		(mob, target, max)				--
--																	--
--	Takes targets shadows on AoE move.								--
--	This is completely crap and should be using actual NIN skill	--
-- 	TODO: fix this													--
--																	--
-- -------------------------------------------------------------------

function MobTakeAoEShadow(mob, target, max)

	-- local chance = 75;

	-- local targetSkill = target:getSkillLevel(NINJUTSU_SKILL);
	-- local mobSkill = getSkillLvl(3, mob:getMainLvl());

	if(target:getMainJob() == JOB_NIN and math.random() < 0.6) then
		max = max - 1;
		if(max < 1) then
			max = 1;
		end
	end

	return math.random(1, max);
end;

-- -------------------------------------------------------------------
--																	--
--		== MobTPMod ==		(TP)									--
--																	--
--	Increase damage based on TP.									--
--																	--
-- -------------------------------------------------------------------

function MobTPMod(tp)
	if(tp >= 300) then
		return 2;
	elseif(tp >= 200) then
		return 1.5;
	end
	return 1;
end;

-- -------------------------------------------------------------------
--																	--
--		== fTP ==		Mob TP Modifier Calculation					--
--																	--
--	The TP modifier function is a straight linear equation between	--
--	the anchor points at 100% and 200%. It is also a straight		--
--	linear equation between the anchor points at 200% and 300%. In	--
--	other words, each percentage point of TP past an anchor point	--
--	(100% or 200%) will increase fTP by 1% of the difference		--
--	between the fTP of the next anchor point and the fTP of the		--
--	previous anchor point. 											--
--																	--
-- -------------------------------------------------------------------

function fTP(tp,ftp1,ftp2,ftp3)
	if(tp<100) then
		tp=100;
	end
	if(tp>=100 and tp<150) then
		return ftp1 + ( ((ftp2-ftp1)/50) * (tp-100));
	elseif(tp>=150 and tp<=300) then
		-- Generate a straight line between fTP2 and fTP3 and find point @ TP
		return ftp2 + ( ((ftp3-ftp2)/150) * (tp-150));
	end
	return 1; -- No fTP mod
end;
